package com.ticket.sass.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ticket.sass.admin.mapper.FilmCinemaMapMapper;
import com.ticket.sass.admin.service.BaseService;
import com.ticket.sass.common.entity.tenant.FilmCinemaMapEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author ywb
 * @since 2024-07-09
 */
@Service
public class FilmCinemaMapServiceImpl extends ServiceImpl<FilmCinemaMapMapper, FilmCinemaMapEntity> implements BaseService<FilmCinemaMapEntity> {
    /**
     * 根据影片ID列表获取影片ID与排序字段的映射表
     *
     * @param filmIds 影片ID列表
     * @return 一个Map对象，键是影片ID，值是排序字段。如果传入的影片ID列表为空，则返回一个空的Map。
     */
    public Map<Long, Integer> getFilmSortMapByFilmIds(List<Long> filmIds) {
        // 如果传入的影片ID列表为空，返回一个空的Map
        if (CollectionUtils.isEmpty(filmIds)) {
            return new HashMap<>();
        }
        
        // 查询符合条件的记录
        QueryWrapper<FilmCinemaMapEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("film_id", filmIds);
        List<FilmCinemaMapEntity> filmCinemaMapsList = this.baseMapper.selectList(queryWrapper);
        
        // 转换为Map并返回
        Map<Long, Integer> filmSortMap = new HashMap<>();
        for (FilmCinemaMapEntity entity : filmCinemaMapsList) {
            filmSortMap.put(entity.getFilmId(), entity.getSort());
        }
        return filmSortMap;
    }
    
    
    @Transactional
    public void saveOrUpdateFilmSort(Long filmId, Integer newSort, List<Long> filmIds) {
        // 同步块或者其他线程安全机制
        synchronized (this) {
            // 获取当前所有排序 注意 filmIds 包括 filmId 但是 filmId 可能没有对应的排序 因为可能是新增
            Map<Long, Integer> filmSortMap = getFilmSortMapByFilmIds(filmIds);
            
            if (newSort == null) {
                newSort = getMaxSort(filmSortMap);
            }
            
            // 查询是否存在给定影片ID的记录
            Integer oldSort = filmSortMap.get(filmId);
            
            if (oldSort != null) {
                // 存在记录
                if (!newSort.equals(oldSort)) {
                    updateSortValues(oldSort, newSort, filmSortMap.keySet());
                    
                    UpdateWrapper<FilmCinemaMapEntity> updateWrapper = new UpdateWrapper<>();
                    updateWrapper.set("sort", newSort);
                    updateWrapper.eq("film_id", filmId);
                    this.baseMapper.update(null, updateWrapper);
                }
            } else {
                if (isSortExists(filmSortMap, newSort)){
                    updateSortValues(999, newSort, filmSortMap.keySet());
                }
                
                // 插入新的记录
                FilmCinemaMapEntity newEntity = new FilmCinemaMapEntity();
                newEntity.setFilmId(filmId);
                newEntity.setSort(newSort);
                this.baseMapper.insert(newEntity);
            }
        }
    }
    
    private void updateSortValues(Integer oldSort, Integer newSort, Set<Long> filmIds) {
        UpdateWrapper<FilmCinemaMapEntity> updateWrapper = new UpdateWrapper<>();
        if (oldSort < newSort) {
            updateWrapper.setSql("sort = sort - 1").gt("sort", oldSort).le("sort", newSort);
        } else {
            updateWrapper.setSql("sort = sort + 1").ge("sort", newSort).lt("sort", oldSort);
        }
        
        updateWrapper.in(filmIds.size() > 0, "film_id", filmIds);
        this.baseMapper.update(null, updateWrapper);
    }
    
    private boolean isSortExists(Map<Long, Integer> filmSortMap, Integer sort) {
        return filmSortMap.containsValue(sort);
    }
    
    private Integer getMaxSort(Map<Long, Integer> filmSortMap) {
        if (filmSortMap == null || filmSortMap.isEmpty()) {
            return 1;
        }
        Integer maxSort = Collections.max(filmSortMap.values());
        return maxSort + 1;
    }
}